﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Text.RegularExpressions;

namespace XNET.Extension
{
    /// <summary>
    /// 字符扩展
    /// </summary>
    public static class StringExtension
    {
        /// <summary>
        /// 字符比较
        /// </summary>
        /// <param name="strA">字符A</param>
        /// <param name="strB">字符B</param>
        /// <param name="comparisonType">类型</param>
        /// <returns></returns>
        public static bool Equals(this string strA, string strB, StringComparison comparisonType)
        {
            return string.Equals(strA, strB, comparisonType);
        }

        /// <summary>
        /// 字符比较
        /// </summary>
        /// <param name="strA">字符A</param>
        /// <param name="strB">字符B</param>
        /// <returns></returns>
        public static bool Equals(this string strA, string strB)
        {
            return string.Equals(strA, strB);
        }

        /// <summary>
        /// 字符格式化
        /// </summary>
        /// <param name="str">字符</param>
        /// <param name="args">参数集合</param>
        /// <returns></returns>
        public static string Format(this string str, params object[] args)
        {
            return string.Format(str, args);
        }

        /// <summary>
        /// 是否为空
        /// </summary>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string value)
        {
            return string.IsNullOrEmpty(value);
        }

        /// <summary>
        /// 查看字符是否指定类型
        /// </summary>
        /// <param name="Value">要比较字符串</param>
        /// <param name="ComparisonType">比较类型</param>
        /// <returns></returns>
        public static bool Is(this string Value, StringCompare ComparisonType)
        {
            if (ComparisonType == StringCompare.CreditCard)
            {
                var CheckSum = 0L;
                Value = Value.Replace("-", string.Empty).Reverse();
                for (var x = 0; x < Value.Length; ++x)
                {
                    if (!Value[x].Is(CharIs.Digit))
                    {
                        return false;
                    }
                    int TempValue = (Value[x] - '0') * (x % 2 == 1 ? 2 : 1);
                    while (TempValue > 0)
                    {
                        CheckSum += TempValue % 10;
                        TempValue /= 10;
                    }
                }
                return (CheckSum % 10) == 0;
            }
            if (ComparisonType == StringCompare.Unicode)
            {
                return string.IsNullOrEmpty(Value) ? true : Regex.Replace(Value, @"[^\u0000-\u007F]", string.Empty) != Value;
            }
            return Value.Is(string.Empty, StringCompare.Anagram);
        }

        /// <summary>
        /// 查看字符是否指定类型
        /// </summary>
        /// <param name="Value1">值1/param>
        /// <param name="Value2">值2</param>
        /// <param name="ComparisonType">比较类型</param>
        /// <returns></returns>
        /// </param>
        public static bool Is(this string Value1, string Value2, StringCompare ComparisonType)
        {
            if (ComparisonType != StringCompare.Anagram)
            {
                return Value1.Is(ComparisonType);
            }
            return new string(Value1.OrderBy(x => x).ToArray()) == new string(Value2.OrderBy(x => x).ToArray());
        }

        /// <summary>
        /// 倒转字符串
        /// </summary>
        /// <param name="Input">字符串</param>
        /// <returns></returns>
        public static string Reverse(this string Input)
        {
            return new string(Input.Reverse<char>().ToArray());
        }

        /// <summary>
        /// 为StringBuilder添加换行
        /// </summary>
        /// <param name="Builder">字符</param>
        /// <param name="Format">字符格式化</param>
        /// <param name="Objects">格式化对象</param>
        /// <returns></returns>
        public static StringBuilder AppendLineFormat(this StringBuilder Builder, string Format, params object[] Objects)
        {
            return Builder.AppendFormat(CultureInfo.InvariantCulture, Format, Objects).AppendLine();
        }

        /// <summary>
        /// 将输入字符居中(如果长度大于输入字符长度) 用填充符填充字符两端
        /// </summary>
        /// <param name="Input">输入字符串</param>
        /// <param name="Length">长度</param>
        /// <param name="Padding">填充字符</param>
        /// <returns></returns>
        public static string Center(this string Input, int Length, string Padding = " ")
        {
            if (Input.IsNullOrEmpty())
            {
                Input = string.Empty;
            }
            var Output = string.Empty;
            for (var x = 0; x < (Length - Input.Length) / 2; ++x)
            {
                Output += Padding[x % Padding.Length];
            }
            Output += Input;
            for (var x = 0; x < (Length - Input.Length) / 2; ++x)
            {
                Output += Padding[x % Padding.Length];
            }
            return Output;
        }

        /// <summary>
        /// 将Base64转换到指定编码
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="EncodingUsing">要转换的编码(默认UTF8)</param>
        /// <returns></returns>
        public static string FromBase64(this string Input, Encoding EncodingUsing)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            var TempArray = Convert.FromBase64String(Input);
            return EncodingUsing.Check(() => new UTF8Encoding()).GetString(TempArray);
        }

        /// <summary>
        /// 将Base64转换为字符数组
        /// </summary>
        /// <param name="Input">字符</param>
        /// <returns></returns>
        public static byte[] FromBase64(this string Input)
        {
            return string.IsNullOrEmpty(Input) ? new byte[0] : Convert.FromBase64String(Input);
        }

        /// <summary>
        /// 过滤所有不符合条件的字符
        /// </summary>
        /// <param name="Input">文本</param>
        /// <param name="Filter">文本正则表达</param>
        /// <returns></returns>
        public static string Keep(this string Input, string Filter)
        {
            if (Input.IsNullOrEmpty() || Filter.IsNullOrEmpty())
            {
                return string.Empty;
            }
            var TempRegex = new Regex(Filter);
            var Collection = TempRegex.Matches(Input);
            var Builder = new StringBuilder();
            foreach (Match Match in Collection)
            {
                Builder.Append(Match.Value);
            }
            return Builder.ToString();
        }

        /// <summary>
        /// 过滤所有不符合条件的字符
        /// </summary>
        /// <param name="Input">字符串</param>
        /// <param name="Filter">预定义过滤</param>
        /// <returns></returns>
        public static string Keep(this string Input, StringFilter Filter)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            var Value = BuildFilter(Filter);
            return Input.Keep(Value);
        }

        /// <summary>
        /// 截取左边字符串
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Length">截取长度</param>
        /// <returns></returns>
        public static string Left(this string Input, int Length)
        {
            return string.IsNullOrEmpty(Input) ? string.Empty : Input.Substring(0, Input.Length > Length ? Length : Input.Length);
        }

        /// <summary>
        /// Calculates the Levenshtein distance
        /// </summary>
        /// <param name="Value1">Value 1</param>
        /// <param name="Value2">Value 2</param>
        /// <returns>The Levenshtein distance</returns>
        public static int LevenshteinDistance(this string Value1, string Value2)
        {
            var Matrix = new int[Value1.Length + 1, Value2.Length + 1];
            for (var x = 0; x <= Value1.Length; ++x)
            {
                Matrix[x, 0] = x;
            }
            for (var x = 0; x <= Value2.Length; ++x)
            {
                Matrix[0, x] = x;
            }
            for (var x = 1; x <= Value1.Length; ++x)
            {
                for (var y = 1; y <= Value2.Length; ++y)
                {
                    var Cost = Value1[x - 1] == Value2[y - 1] ? 0 : 1;
                    Matrix[x, y] = new int[] { Matrix[x - 1, y] + 1, Matrix[x, y - 1] + 1, Matrix[x - 1, y - 1] + Cost }.Min();
                    if (x > 1 && y > 1 && Value1[x - 1] == Value2[y - 2] && Value1[x - 2] == Value2[y - 1])
                    {
                        Matrix[x, y] = new int[] { Matrix[x, y], Matrix[x - 2, y - 2] + Cost }.Min();
                    }
                }
            }

            return Matrix[Value1.Length, Value2.Length];
        }

        /// <summary>
        /// 在字符串左边替换指定字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="EndPosition">指定位置</param>
        /// <param name="Mask">替换字符</param>
        /// <returns></returns>
        public static string MaskLeft(this string Input, int EndPosition = 4, char Mask = '#')
        {
            var Appending = string.Empty;
            for (var x = 0; x < EndPosition; ++x)
            {
                Appending += Mask;
            }
            return Appending + Input.Remove(0, EndPosition);
        }

        /// <summary>
        /// 在字符串右面替换指定字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="StartPosition">指定位置</param>
        /// <param name="Mask">替换字符</param>
        /// <returns></returns>
        public static string MaskRight(this string Input, int StartPosition = 4, char Mask = '#')
        {
            if (StartPosition > Input.Length)
            {
                return Input;
            }
            var Appending = string.Empty;
            for (var x = 0; x < Input.Length - StartPosition; ++x)
            {
                Appending += Mask;
            }
            return Input.Remove(StartPosition) + Appending;
        }

        /// <summary>
        /// 返回字符在字符串中出现次数
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Match">匹配规则</param>
        /// <returns></returns>
        public static int NumberTimesOccurs(this string Input, string Match)
        {
            return string.IsNullOrEmpty(Input) ? 0 : new Regex(Match).Matches(Input).Count;
        }

        /// <summary>
        /// 删除字符串中指定字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Filter">文本删除的正则表达</param>
        /// <returns></returns>
        public static string Remove(this string Input, string Filter)
        {
            if (string.IsNullOrEmpty(Input) || string.IsNullOrEmpty(Filter))
            {
                return Input;
            }
            return new Regex(Filter).Replace(Input, string.Empty);
        }

        /// <summary>
        /// 删除字符串中指定字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Filter">文本删除的正则表达</param>
        /// <returns></returns>
        public static string Remove(this string Input, StringFilter Filter)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            var Value = BuildFilter(Filter);
            return Input.Remove(Value);
        }

        /// <summary>
        /// 将字符串中指定类型的字符替换
        /// </summary>
        /// <param name="Input">字符串</param>
        /// <param name="Value">要替换的字符</param>
        /// <param name="Filter">指定类型</param>
        /// <returns></returns>
        public static string Replace(this string Input, StringFilter Filter, string Value = "")
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            var FilterValue = BuildFilter(Filter);
            return new Regex(FilterValue).Replace(Input, Value);
        }

        /// <summary>
        /// 截取右边指定长度字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Length">长度</param>
        /// <returns></returns>
        public static string Right(this string Input, int Length)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            Length = Input.Length > Length ? Length : Input.Length;
            return Input.Substring(Input.Length - Length, Length);
        }

        /// <summary>
        /// 从字符右面开始删除字符列表中的字符。
        /// </summary>
        /// <param name="Input">字符串</param>
        /// <param name="Characters">字符列表（默认空格）</param>
        /// <returns></returns>
        public static string StripRight(this string Input, string Characters = " ")
        {
            if (string.IsNullOrEmpty(Input))
            {
                return Input;
            }
            if (string.IsNullOrEmpty(Characters))
            {
                return Input;
            }
            var Position = Input.Length - 1;
            for (var x = Input.Length - 1; x >= 0; --x)
            {
                if (!Characters.Contains(Input[x]))
                {
                    Position = x + 1;
                    break;
                }
            }
            return Input.Left(Position);
        }

        /// <summary>
        /// 过滤XML内容中非法的字符
        /// </summary>
        /// <param name="Content">XML内容</param>
        /// <returns></returns>
        public static string StripIllegalXML(this string Content)
        {
            if (string.IsNullOrEmpty(Content))
            {
                return string.Empty;
            }
            var Builder = new StringBuilder();
            foreach (char Char in Content)
            {
                if (Char == 0x9
                    || Char == 0xA
                    || Char == 0xD
                    || (Char >= 0x20 && Char <= 0xD7FF)
                    || (Char >= 0xE000 && Char <= 0xFFFD))
                {
                    Builder.Append(Char);
                }
            }
            return Builder.ToString().Replace('\u2013', '-').Replace('\u2014', '-')
                .Replace('\u2015', '-').Replace('\u2017', '_').Replace('\u2018', '\'')
                .Replace('\u2019', '\'').Replace('\u201a', ',').Replace('\u201b', '\'')
                .Replace('\u201c', '\"').Replace('\u201d', '\"').Replace('\u201e', '\"')
                .Replace("\u2026", "...").Replace('\u2032', '\'').Replace('\u2033', '\"')
                .Replace("`", "\'")
                .Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;")
                .Replace("\"", "&quot;").Replace("\'", "&apos;");
        }

        /// <summary>
        /// Converts from the specified encoding to a base 64 string
        /// </summary>
        /// <param name="Input">Input string</param>
        /// <param name="OriginalEncodingUsing">The type of encoding the string is using (defaults to UTF8)</param>
        /// <returns>Bas64 string</returns>
        public static string ToBase64(this string Input, Encoding OriginalEncodingUsing = null)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            var TempArray = OriginalEncodingUsing.Check(new UTF8Encoding()).GetBytes(Input);
            return Convert.ToBase64String(TempArray);
        }

        /// <summary>
        /// 将字符转换为指定格式字节数组
        /// </summary>
        /// <param name="Input">input string</param>
        /// <param name="EncodingUsing">The type of encoding the string is using (defaults to UTF8)</param>
        /// <returns>the byte array representing the string</returns>
        public static byte[] ToByteArray(this string Input, Encoding EncodingUsing = null)
        {
            return string.IsNullOrEmpty(Input) ? null : EncodingUsing.Check(new UTF8Encoding()).GetBytes(Input);
        }

        /// <summary>
        /// 基于指定类型的字符格式化
        /// </summary>
        /// <param name="Input">字符/param>
        /// <param name="Case">格式化类型</param>
        /// <returns></returns>
        /// </param>
        public static string ToString(this string Input, StringCase Case)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return string.Empty;
            }
            if (Case == StringCase.FirstCharacterUpperCase)
            {
                var InputChars = Input.ToCharArray();
                for (var x = 0; x < InputChars.Length; ++x)
                {
                    if (InputChars[x] != ' ' && InputChars[x] != '\t')
                    {
                        InputChars[x] = char.ToUpper(InputChars[x], CultureInfo.InvariantCulture);
                        break;
                    }
                }
                return new string(InputChars);
            }
            else
            {
                if (Case == StringCase.SentenceCapitalize)
                {
                    var Seperator = new string[] { ".", "?", "!" };
                    var InputStrings = Input.Split(Seperator, StringSplitOptions.None);
                    for (var x = 0; x < InputStrings.Length; ++x)
                    {
                        if (!string.IsNullOrEmpty(InputStrings[x]))
                        {
                            var TempRegex = new Regex(InputStrings[x]);
                            InputStrings[x] = InputStrings[x].ToString(StringCase.FirstCharacterUpperCase);
                            Input = TempRegex.Replace(Input, InputStrings[x]);
                        }
                    }
                    return Input;
                }
                else
                {
                    if (Case == StringCase.TitleCase)
                    {
                        var Seperator = new string[] { " ", ".", "\t", System.Environment.NewLine, "!", "?" };
                        var InputStrings = Input.Split(Seperator, StringSplitOptions.None);
                        for (var x = 0; x < InputStrings.Length; ++x)
                        {
                            if (!string.IsNullOrEmpty(InputStrings[x])
                            && InputStrings[x].Length > 3)
                            {
                                var TempRegex = new Regex(InputStrings[x].Replace(")", @"\)").Replace("(", @"\(").Replace("*", @"\*"));
                                InputStrings[x] = InputStrings[x].ToString(StringCase.FirstCharacterUpperCase);
                                Input = TempRegex.Replace(Input, InputStrings[x]);
                            }
                        }
                        return Input;
                    }
                }
            }
            return Input;
        }

        /// <summary>
        /// 基于对象属性格式化字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Object">格式化字符的对象</param>
        /// <param name="StartSeperator">要格式化属性开始标志</param>
        /// <param name="EndSeperator">要格式化属性结束标志</param>
        /// <returns>The formatted string</returns>
        public static string ToString(this string Input, object Object, string StartSeperator = "{", string EndSeperator = "}")
        {
            if (Object == null)
            {
                return Input;
            }
            Object.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(x => x.CanRead)
                .ForEach(x =>
                {
                    var Value = x.GetValue(Object, null);
                    Input = Input.Replace(StartSeperator + x.Name + EndSeperator, Value == null ? string.Empty : Value.ToString());
                });
            return Input;
        }

        /// <summary>
        /// 基于键值对字符替换，将字符串中的KEY字符替换为VALUE字符
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Pairs">键值对，将字符串中的KEY字符替换为VALUE字符</param>
        /// <returns></returns>
        public static string ToString(this string Input, params KeyValuePair<string, string>[] Pairs)
        {
            if (string.IsNullOrEmpty(Input))
            {
                return Input;
            }
            foreach (KeyValuePair<string, string> Pair in Pairs)
            {
                Input = Input.Replace(Pair.Key, Pair.Value);
            }
            return Input;
        }

        /// <summary>
        /// 使用正则表达式格式化字符串
        /// </summary>
        /// <param name="Input">字符</param>
        /// <param name="Format">正则表达式</param>
        /// <param name="OutputFormat">输出格式</param>
        /// <param name="Options">正则表达式枚举</param>
        /// <returns></returns>
        public static string ToString(this string Input, string Format, string OutputFormat, RegexOptions Options = RegexOptions.None)
        {
            return Regex.Replace(Input, Format, OutputFormat, Options);
        }

        private static string BuildFilter(StringFilter Filter)
        {
            var FilterValue = string.Empty;
            var Separator = string.Empty;
            if (Filter.HasFlag(StringFilter.Alpha))
            {
                FilterValue += Separator + "[a-zA-Z]";
                Separator = "|";
            }
            if (Filter.HasFlag(StringFilter.Numeric))
            {
                FilterValue += Separator + "[0-9]";
                Separator = "|";
            }
            if (Filter.HasFlag(StringFilter.FloatNumeric))
            {
                FilterValue += Separator + @"[0-9\.]";
                Separator = "|";
            }
            if (Filter.HasFlag(StringFilter.ExtraSpaces))
            {
                FilterValue += Separator + @"[ ]{2,}";
                Separator = "|";
            }
            return FilterValue;
        }

        /// <summary>
        /// 删除目录非法字符
        /// </summary>
        /// <param name="DirectoryName">目录名</param>
        /// <param name="ReplacementChar">替换字符</param>
        /// <returns></returns>
        public static string RemoveIllegalDirectoryNameCharacters(this string DirectoryName, char ReplacementChar = '_')
        {
            if (string.IsNullOrEmpty(DirectoryName))
            {
                return DirectoryName;
            }
            foreach (char Char in Path.GetInvalidPathChars())
            {
                DirectoryName = DirectoryName.Replace(Char, ReplacementChar);
            }
            return DirectoryName;
        }

        /// <summary>
        /// 删除文件非法字符
        /// </summary>
        /// <param name="FileName">文件名</param>
        /// <param name="ReplacementChar">替换字符</param>
        /// <returns></returns>
        public static string RemoveIllegalFileNameCharacters(this string FileName, char ReplacementChar = '_')
        {
            if (string.IsNullOrEmpty(FileName))
            {
                return FileName;
            }
            foreach (char Char in Path.GetInvalidFileNameChars())
            {
                FileName = FileName.Replace(Char, ReplacementChar);
            }
            return FileName;
        }
    }

    /// <summary>
    /// 字符串规则
    /// </summary>
    public enum StringCase
    {
        /// <summary>
        /// 每句第一个字母大写,(分隔符 '.','!','?')
        /// </summary>
        SentenceCapitalize,
        /// <summary>
        /// 第一个字母大写
        /// </summary>
        FirstCharacterUpperCase,
        /// <summary>
        /// 每个单词第一个字母大写(单词超过3个字符 分隔符 '空格','.','\t','\r\n','!','?')
        /// </summary>
        TitleCase
    }

    /// <summary>
    /// 字符比较类型
    /// </summary>
    public enum StringCompare
    {
        /// <summary>
        /// 是否银行卡号码
        /// </summary>
        CreditCard,
        /// <summary>
        /// Is this an anagram?
        /// </summary>
        Anagram,
        /// <summary>
        /// 是否Unicode类型
        /// </summary>
        Unicode
    }

    /// <summary>
    /// 过滤类型
    /// </summary>
    [Flags]
    public enum StringFilter
    {
        /// <summary>
        /// 字母字符
        /// </summary>
        Alpha = 1,
        /// <summary>
        /// 多个空白字符
        /// </summary>
        ExtraSpaces = 8,
        /// <summary>
        /// 十进制数字
        /// </summary>
        FloatNumeric = 4,
        /// <summary>
        /// 数字字符
        /// </summary>
        Numeric = 2
    }
}
